using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;

using Common.Interfaces;
using System.Diagnostics;
using Common.Gui.GuiWinFormsLib.Helpers;

namespace Common.Gui.GuiWinFormsLib.Controls
{
	/// <summary>
	/// used for switcher controls switching between dockable panels 
	/// </summary>
	internal interface ISwitcher : IComponent
	{
		/// <summary>
		/// the dockagle panels which this switcher belongs to 
		/// </summary>
		IDockablePanel AttachedPanel
		{
			get;
			set;
		}

		///// <summary>
		///// container, taht contains this. switcher
		///// </summary>
		//DockingContainer ParentContainer
		//{
		//    get;
		//    set;
		//}
		
		/// <summary>
		/// switcher default height,
		/// the height could change e.g. by heighlithing the switcher 
		/// and we need to know the default height
		/// </summary>
		int DefaultHeight
		{
			get;
			set;
		}

		/// <summary>
		/// switcher text 
		/// </summary>
		string TitleText
		{
			get;
			set;
		}

		/// <summary>
		/// gets or sets wheter the switcher is active
		/// and its attached dockable panel is visible
		/// </summary>
		bool Activated
		{
			get;
			set;
		}

		/// <summary>
		/// width or heigth, depending on the alignment
		/// </summary>
		int Length
		{
			get;
			set;
		}
	}
	
	internal partial class SwitcherButton : UserControl, ISwitcher
	{
		/// <summary>
		///  font used for text rendering
		/// </summary>
		protected Font font;

		protected string titleText;
		
		protected Color color1;
		protected Color color2;
		/// <summary>
		/// temp color used for background color1 change
		/// after mouse events
		/// </summary>
		protected Color tempColor1;
		/// <summary>
		/// temp color used for background color2 change
		/// after mouse events
		/// </summary>
		protected Color tempColor2;
		
		protected Brush brush;

		private int length;

		/// <summary>
		/// width or heigth, depending on the alignment
		/// </summary>
		public int Length
		{
			get { return length; }
			set 
			{ 
				length = value;
				this.UpdateGeometry();
			}
		}
		
		protected IDockablePanel attachedPanel;
		
		/// <summary>
		/// switcher text 
		/// </summary>
		public string TitleText
		{
			get { return titleText; }
			set { titleText = value; }
		}

		/// <summary>
		/// second color used in background gradient paint
		/// </summary>
		public Color Color2 {
			get {
				return color2;
			}
			set {
				color2 = value;
			}
		}
		
		/// <summary>
		/// first color used in background gradient paint 
		/// </summary>
		public Color Color1 {
			get {
				return color1;
			}
			set {
				color1 = value;
			}
		}
		
		/// <summary>
		/// attached dockable panel,
		/// switcher changes its look depending on panel state 
		/// </summary>
		public IDockablePanel AttachedPanel {
			get {
				return attachedPanel;
			}
			set {
				attachedPanel = value;
				HandleDockablePanelStateChanged(value);
				this.attachedPanel.HandleDockablePanelStateChanged += HandleDockablePanelStateChanged;
			}
		}    	
		
		/// <summary>
		/// the default height we can return to after highlight 
		/// </summary>
		public int DefaultHeight
		{
			get;
			set;
		}

		/// <summary>
		/// true if this switcher is active and attached panel is visible
		/// </summary>
		public bool Activated
		{
			get;
			set;
		}


		private bool isAlignedToSide;
		
		/// <summary>
		/// #ctor - init components, colors, declare events 
		/// </summary>
		public SwitcherButton()
		{
			InitializeComponent();

			this.color2 = Color.Yellow;
			this.color1 = Color.White;
			
			this.Paint += new PaintEventHandler(SwitcherButton_Paint);
			this.Click += new EventHandler(SwitcherButton_Click);
			this.MouseLeave += new EventHandler(SwitcherButton_MouseLeave);
			this.MouseEnter += new EventHandler(SwitcherButton_MouseEnter);
			this.SizeChanged += new EventHandler(SwitcherButton_SizeChanged);
			this.MouseDown += new MouseEventHandler(SwitcherButton_MouseDown);
			this.MouseUp += new MouseEventHandler(SwitcherButton_MouseUp);

			this.ParentChanged += new EventHandler(SwitcherButton_ParentChanged);
		}

		/// <summary>
		/// will update width and height accordingly to dockable panel status and current alignment
		/// </summary>
		private void UpdateGeometry()
		{
			var height = ComputeHeight();

			if (this.isAlignedToSide)
			{
				this.Width = height;
				this.Height = this.Length;
			}
			else
			{
				this.Width = this.Length;
				this.Height = height;
			}
		}

		/// <summary>
		/// If parent is supporting reshaping we need to know - like when the whole panel is aligned to side,
		/// we want to change geometry of switcher panels and align them too
		/// </summary>
		/// <param name="sender">
		/// A <see cref="System.Object"/>
		/// </param>
		/// <param name="e">
		/// A <see cref="EventArgs"/>
		/// </param>
		void SwitcherButton_ParentChanged(object sender, EventArgs e)
		{
			if (this.Parent is ContainerControlPanel)
				(this.Parent as ContainerControlPanel).OnReshape += new EventHandler(SwitcherButton_OnReshape);
			else if (this.Parent == null)
				Logging.Logger.AddWarning(string.Format("Parent of {0} was set to null!", this.ToString() ));
			else
				Logging.Logger.AddWarning(string.Format("Unexpected parent for {0} -> {1}", this.ToString(), this.Parent.ToString() ));
		}

		/// <summary>
		/// the geometry of parent changed - alignment chagned 
		/// </summary>
		/// <param name="sender">
		/// A <see cref="System.Object"/>
		/// </param>
		/// <param name="e">
		/// A <see cref="EventArgs"/>
		/// </param>
		protected void SwitcherButton_OnReshape(object sender, EventArgs e)
		{
			var parent = (sender as ContainerControlPanel);
			if (parent != null)
			{
				this.SuspendLayout();
				this.isAlignedToSide = parent.IsAlignedOnSide;

				this.UpdateGeometry();

				if (parent.IsAlignedOnSide)
				{
					this.Location = new Point(0, this.Location.X);
				}
				else
				{
					this.Location = new Point(this.Location.Y, 0);
				}
				this.ResumeLayout(true);
				this.Invalidate();
				//Console.WriteLine(this.Size.ToString()); 
				//Logging.Logger.AddInfo(this.titleText + " switcher OnReshape");
			}
		}

		protected void HandleDockablePanelStateChanged(object sender)
		{
			//Debug.Assert(sender != null, "sender is null.");
			
			this.UpdateGeometry();

			//this.Invalidate();
			//Logging.Logger.AddInfo("Switcher: Panel state changed: " + sender.ToString());
		}

		/// <summary>
		/// Compute height depending on state of attached panel
		/// </summary>
		/// <param name="panel">attached dockable panel</param>
		private int ComputeHeight()
		{
			if (this.attachedPanel == null)
				return this.DefaultHeight;

			var height = this.DefaultHeight;
			switch (this.attachedPanel.CurrentState)
			{
				case DockablePanelState.Floating:
				case DockablePanelState.Hidden:
					height = Math.Max(this.DefaultHeight, 4);
					break;
				case DockablePanelState.Maximalized:
					break;
				case DockablePanelState.Normal:
					height = this.Parent.Height;
					break;
				default:
					Logging.Logger.AddInfo("Switcher: Unknown panel state: " + this.attachedPanel.CurrentState.ToString());
					break;
			}

			return height;
		}
		
		void SwitcherButton_MouseDown (object sender, MouseEventArgs e)
		{
			System.Diagnostics.Debug.Assert(this.color1 != default(Color));
			
			this.tempColor1 = this.color1;
			this.color1 = Color.Red;
			this.UpdateBrush();
		}
			
		void SwitcherButton_MouseUp (object sender, MouseEventArgs e)
		{
			System.Diagnostics.Debug.Assert(tempColor1 != default(Color));
			
			this.color1 = tempColor1;
			this.UpdateBrush();
		}

		void SwitcherButton_SizeChanged(object sender, EventArgs e)
		{
			float height = ComputeHeight();
			height = height - height / 4;
			if (height > 0)
			{
				this.font = new Font("Arial", height, GraphicsUnit.Pixel);

			    this.UpdateBrush(); 
			}
		}
		
		/// <summary>
		/// updates currently used gradient brush for control's background,
		/// brush colors are determined by current Color1, Color2 properties
		/// </summary>
		protected void UpdateBrush ()
		{
			var height = this.ComputeHeight();

			if (this.Activated && !this.isAlignedToSide)
				this.brush = new LinearGradientBrush(new Rectangle(0, 0, this.length, height), this.color1, this.color2, LinearGradientMode.Vertical);
			else if (this.Activated && this.isAlignedToSide)
				this.brush = new LinearGradientBrush(new Rectangle(0, 0, height, this.length), this.color1, this.color2, LinearGradientMode.Horizontal); 
//			else if (this.Parent != null)
//				this.brush = new SolidBrush(this.Parent.ForeColor);
			else
			{
				//var clr = Color.FromArgb(255, this.Parent.BackColor);
				var clr = Color.Transparent;
				this.brush = new SolidBrush(clr);
			}
				//this.brush = new HatchBrush( HatchStyle.Percent05, this.color1, this.color2); 
			this.Invalidate(true);
		}

		void SwitcherButton_MouseLeave(object sender, EventArgs e)
		{			
			System.Diagnostics.Debug.Assert(tempColor2 != default(Color));
			
			this.color2 = tempColor2;
			this.UpdateBrush();
		}

		void SwitcherButton_MouseEnter(object sender, EventArgs e)
		{
			System.Diagnostics.Debug.Assert(this.color2 != default(Color));
			
			this.tempColor2 = this.color2;
			this.color2 = Color.YellowGreen;
			this.UpdateBrush();
		}

		void SwitcherButton_Click(object sender, EventArgs e)
		{
			
		}

		void SwitcherButton_Paint(object sender, PaintEventArgs e)
		{
			if (this.font != null)
			{
				Graphics g = e.Graphics;
				
				int radius = 3;
				g.FillRoundRect(this.brush, 0, 0, this.Width, this.Height,radius);
				g.DrawRoundRect(new Pen (this.color1, 2), 1,1,this.Width -2, this.Height - 2, radius);

				SizeF textSize = g.MeasureString(this.TitleText, font);

				if (textSize.Width > this.Width)
					this.Length = (int) textSize.Width + 50;

				//float positionY = this.Height / 2 - textSize.Height / 2;
				//float positionX = this.Width / 2 - textSize.Width / 2;
				var positionY = this.ComputeHeight() / 2 - textSize.Height / 2;
				var positionX = this.length / 2 - textSize.Width / 2;

				if (this.isAlignedToSide)
				{
					var drawFormat = new System.Drawing.StringFormat(StringFormatFlags.DirectionVertical);

					g.DrawString(this.TitleText, this.font, Brushes.Black, new PointF(positionY, positionX), drawFormat); 
				}
				else
					g.DrawString(this.TitleText, this.font, Brushes.Black, new PointF(positionX, positionY)); 
			}
		}

		public override string ToString()
		{
			var str = string.Format("[Switcher: {0}; Active: {1}]", this.titleText, this.Activated.ToString());
			return str;
		}
	}
}